﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web;
using System.IO;
using DotNetNuke.Common;
using DotNetNuke.Data;
using System.Data.SqlClient;
using DotNetNuke.Modules.PowerShell.Services.Rss;
using ICSharpCode.SharpZipLib.Zip;
using DotNetNuke.Entities.Portals;

namespace DotNetNuke.Modules.PowerShell.Contexts
{
	public class UpgradeContext : BaseContext
	{
		public override void Process(Args.IContextArgs args)
		{
			base.Process(args);

			if (IsValid)
			{
				switch (args.Action)
				{
					case "backup":
						Backup();
						break;
					case "check":
						CheckUpgrade();
						break;
					default:
						AddResult("No Action");
						break;
				}
			}
		}

		#region Backup Methods

		private void Backup()
		{
			BackupDatabase();

			var package = CreateSitePackage();

			AddResult(package);
		}

		private string CreateSitePackage()
		{
			try
			{
				var zipPath = Path.Combine(Globals.ApplicationMapPath, DateTime.Now.ToString("yyyyMMddHHmmss") + ".zip");
				string[] filenames = Directory.GetFiles(Globals.ApplicationMapPath, "*.*", SearchOption.AllDirectories);
				bool isAborted = false;
				using (ZipOutputStream s = new ZipOutputStream(File.Create(zipPath)))
				{
					s.SetLevel(9);
					byte[] buffer = new byte[4096];
					foreach (string file in filenames)
					{
						if(!HttpContext.Current.Response.IsClientConnected)
						{
							isAborted = true;
							break;
						}

						if (Path.GetExtension(file).ToLowerInvariant() == ".mdf"
							|| Path.GetExtension(file).ToLowerInvariant() == ".ldf"
							|| Path.GetExtension(file).ToLowerInvariant() == ".log"
							|| Path.GetExtension(file).ToLowerInvariant() == ".txt"
							)
						{
							continue;
						}
						string zipFile = Path.GetFullPath(file).Replace(Globals.ApplicationMapPath + "\\", "");
						ZipEntry entry = new ZipEntry(zipFile);
						entry.DateTime = File.GetLastAccessTime(file);
						s.PutNextEntry(entry);
						using (FileStream fs = File.OpenRead(file))
						{
							int sourceBytes;
							do
							{
								sourceBytes = fs.Read(buffer, 0, buffer.Length);
								s.Write(buffer, 0, sourceBytes);
							} while (sourceBytes > 0);
						}
					}
					s.Finish();
					s.Close();
				}

				if(isAborted)
				{
					File.Delete(zipPath);
					zipPath = "Operation Abort";
				}

				return string.Format("http://{0}/{1}", PortalSettings.Current.PortalAlias.HTTPAlias, Path.GetFileName(zipPath));
			}
			catch (Exception ex)
			{
				return ex.Message;
			}
		}

		private string BackupDatabase()
		{
			var backName = DateTime.Now.ToString("yyyyMMddHHmmss") + ".bak";
			var backPath = Path.Combine(Globals.ApplicationMapPath, backName);
			var dbName = GetDBName();
			var backSql = string.Format("BACKUP DATABASE [{0}] TO DISK='{1}'", dbName, backPath);
			DataProvider.Instance().ExecuteScript(backSql);
			return backName;
		}

		private string GetDBName()
		{
			var dbName = string.Empty;
			using (var connection = new SqlConnection(DataProvider.Instance().ConnectionString))
			{
				dbName = connection.Database;
			}

			if (string.IsNullOrEmpty(dbName))
			{
				foreach (var config in DataProvider.Instance().ConnectionString.Split(';'))
				{
					if (config.IndexOf("AttachDBFilename") > -1)
					{
						dbName = config.Substring(config.IndexOf("=") + 1);
						dbName = Path.Combine(Globals.ApplicationMapPath, dbName.Replace("|DataDirectory|", "App_Data\\"));
						break;
					}
				}
			}

			return dbName;
		}

		#endregion

		#region Upgrade Methods

		private void CheckUpgrade()
		{
			var rss =
				new RssContent(
					"http://dotnetnuke.codeplex.com/project/feeds/rss?ProjectRSSFeed=codeplex%3a%2f%2frelease%2fdotnetnuke");
			var versionRegex = new Regex("(\\d\\d\\.\\d\\d\\.\\d\\d)[ ]+\\(", RegexOptions.Compiled);
			var latestVersion = (from item in rss.Items
			                     where versionRegex.IsMatch(item.Title)
			                     select new
			                            	{
			                            		Version = new Version(versionRegex.Match(item.Title).Groups[1].Value),
												Url = item.Link
			                            	}).First();

			var currVersion = Globals.DataBaseVersion;
			if(latestVersion.Version > currVersion)
			{
				AddResult(string.Format("The new version {0} is available, if you want to auto update to the latest version, please enter command 'upgrade update', "+
				"else if you want to see more release information, please visit  <a href=\"{1}\" target=\"_blank\">{1}</a>.",
				latestVersion.Version, latestVersion.Url));
			}
			else
			{
				AddResult("Your application is up to date.");
			}
		}


		//download url:http://download.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=dotnetnuke&DownloadId=152068&FileTime=129295918597730000&Build=17831

		#endregion

		public override string Help
		{
			get { return "Upgrade Context"; }
		}
	}
}